import { containsPoint } from './utils/index.js';
import { TextCursor } from './Text.Cursor.js';
import { TextLine } from './Text.Line.js'
import { EventDispatcher } from './EventDispatcher.js';
import { RectRubber } from './Rubber.Rect.js';

class TextParagraph extends EventDispatcher {

    constructor(x = 0, y = 0) {
        super();
        this._x = x;
        this._y = y;

        this.forceState = 'normal';

        this.activeTextLine = new TextLine(x, y);
        this.textCursor = new TextCursor(x, y);
        this.textLines = [this.activeTextLine];
        this.lineGap = 6;
        this.currentIndex = 0;

        this.rubber = new RectRubber();
    }

    setup() {

    }

    /**
     * 行数
     */
    get numberOfRows() {
        return this.textLines.length;
    }

    get text() {
        return this.textLines.map(textLine => textLine.text).join('\n');
    }

    get _active() {
        return this.textLines[this.currentIndex];
    }

    setPosition(x, y) {
        this.x = x;
        this.y = y;
    }

    get x() {
        return this._x
    }

    get y() {
        return this._y
    }

    set x(v) {
        let offsetX = v - this._x
        this._x = v
        this.textLines.forEach(line => {
            line.x += offsetX
        })
    }

    set y(v) {
        let offsetY = v - this._y
        this._y = v
        this.textLines.forEach(line => {
            line.y += offsetY
        })
    }

    set width(v) {

    }

    set height(v) {

    }

    // 根据鼠标位置 找出caret所在位置 并且设置caret
    setCaretByPos(context, x, y) {
        let h = this.activeTextLine.getHeight(context) + this.lineGap

        let left = x - this.x
        let top = y - this.y

        let index = Math.floor(top / h)

        if(index < 0 || index > this.numberOfRows) {
            return;
        }

        this.currentIndex = index;
        this.activeTextLine = this.textLines[this.currentIndex];

        // let caretIndex = Math.floor(left / letterWidth)
        // console.log('caretIndex', caretIndex);
        // this.activeTextLine.caret = caretIndex

        // function binaryMeasureText(text) {
        //     let low = 0
        //     let high = text.length
        //     while (low < high) {
        //         let middle = (low + high) >> 1;
        //         let subTxt = text.substring(low, middle);
        //         let width = context.measureText(subTxt).width;
        //         console.log(subTxt);
        //         let diff = left - width;
        //         if (diff > 0) {
        //             low = middle + 1
        //         }
        //         else if (diff < 0) {
        //             high = middle
        //         } 
        //         else if (Math.abs(diff) < 1) {
        //             return middle
        //         }

        //     }
        //     return -1
        // }
        // let letterWidth = this.activeTextLine.getLetterWidth(context);

        function indexOfCaret(text, left) {
            let s = ''
            for (let i = 0; i < text.length; i++) {
                s = s + text[i]
                let w = context.measureText(s).width
                let diff = Math.abs(w - left);
                if (diff < 3) {
                    return i
                }
            }

            return -1

        }

        let caretIndex = indexOfCaret(this.activeTextLine.text, left)
        console.log('caretIndex', caretIndex);
        this.activeTextLine.caret = caretIndex;
    }


    /**
     * 指定的点是否在段落内
     * @param {*} context 
     * @param {*} x 
     * @param {*} y 
     * @returns 
     */
    isPointInside(context, x, y) {
        let rect = this.getBoundingRect(context);
        return containsPoint(rect, x, y);
    }

    /**
     * 指定的点是否在某一行
     * @param {*} context 
     * @param {*} x 
     * @param {*} y 
     * @returns 
     */
    isPointInLine(context, x, y) {
        return this.textLines.some(l => l.containsPoint(context, x, y));
    }

    /**
     * 在当前行插入文本
     * @param {*} text 
     */
    insertText(text) {
        this.activeTextLine.insert(text);
    }

    /**
     * 处理退格操作
     */
    backspace() {
        if (this.activeTextLine.caret == 0) {
            if (this.numberOfRows > 1) {
                this.textLines.pop()
                this.currentIndex--
                this.activeTextLine = this.textLines[this.numberOfRows - 1]
            }
        } else {
            this.activeTextLine.removeCharBeforeCaret()
        }
    }

    homeCursor() {
        this.activeTextLine.homeCursor()
    }
    endCursor() {
        this.activeTextLine.endCursor()
    }

    forwardCursor() {
        this.activeTextLine.forwardCursor()
    }

    backwardCursor() {
        this.activeTextLine.backwardCursor()
    }

    /**
     * 光标向上一行
     */
    upCursor() {
        console.log(this.currentIndex);
        if (this.currentIndex > 0) {
            this.activeTextLine = this.textLines[--this.currentIndex]
        }
    }

    /**
     * 光标向下一行
     */
    downCursor() {
        console.log(this.currentIndex);
        if (this.currentIndex < this.numberOfRows - 1) {
            this.activeTextLine = this.textLines[++this.currentIndex]
        }
    }

    /**
     * 在当前光标处新增一行
     * @param {*} context 
     */
    insertLine(context) {
        let h = this.activeTextLine.getHeight(context) + this.lineGap
        let x = this.x
        let y = this.y + h * (this.currentIndex + 1)

        let caret = this.activeTextLine.caret
        let txt = this.activeTextLine.text
        let nl = new TextLine(x, y)


        this.activeTextLine.text = txt.slice(0, caret)

        nl.caret = 0
        nl.text = txt.slice(caret)

        // 插入
        this.activeTextLine = nl
        this.textLines.splice(this.currentIndex + 1, 0, nl)

        // 更新被折行的元素位置
        let endIndex = this.currentIndex + 2
        let end = this.textLines.slice(endIndex)
        end.forEach((e, i) => {
            e.y = this.y + h * (i + endIndex)
        })
        // 
        this.currentIndex++
    }

    /**
     * 给段落最后新增一行
     * @param {*} context 
     */
    newLine(context) {
        console.log('new line');
        let x = this.x
        let y = this.y + (this.activeTextLine.getHeight(context) + this.lineGap) * this.numberOfRows
        let nl = new TextLine(x, y)
        this.activeTextLine = nl
        this.textLines.push(nl)
        this.currentIndex++
    }

    update(context, ox, oy) {
        // 更新光标
        if (this.textCursor) {
            this.updateCursorPosition(context);
            this.textCursor.update();
        }
        // 更新行
        this.textLines.forEach(textLine => {
            textLine.update();
        });

        // 跟新操作边框
        let rect = this.getBoundingRect(context);

        this.rubber.update({
            x: rect.x,
            y: rect.y,
            w: rect.width,
            h: rect.height
        });

    }


    draw(context, ox, oy) {
        this.drawBackground(context, ox, oy)
        this.textLines.forEach(textLine => {
            textLine.draw(context, ox, oy)
        })
        if (this.textCursor) {
            this.textCursor.draw(context, ox, oy)
        }

        if (this.forceState == 'selected') {
            this.drawHoverBox(context, ox, oy);
            this.rubber.draw(context, ox, oy);
        }
        if (this.forceState == 'focus') {
            this.drawHoverBox(context, ox, oy);
        }
    }


    drawHoverBox(context, ox, oy) {
        context.save();
        context.beginPath();

        let rect = this.getBoundingRect(context);

        context.lineWidth = 2;
        context.strokeStyle = '#009DFF';
        context.rect(rect.x + ox, rect.y + oy, rect.width, rect.height);
        context.stroke();
        context.restore();
    }

    updateCursorPosition(context) {
        if (this.activeTextLine) {
            let cursorPos = this.activeTextLine.getCursorPosition(context);
            this.textCursor.x = cursorPos.x;
            this.textCursor.y = cursorPos.y;
        }
    }

    drawBackground(context, ox, oy) {
        const { x, y, width, height } = this.getBoundingRect(context);
        context.save();
        context.fillStyle = 'rgba(255, 255, 255, 0.5)';
        context.fillRect(x + ox, y + oy, width, height);
        context.restore();
    }

    getBoundingRect(context) {
        if (!context) {
            throw new ReferenceError('no context')
        }

        let width = 0;
        let height = 0;

        if (this.numberOfRows !== 0) {
            let widths = this.textLines.map(l => l.getWidth(context));
            let h1 = this.textLines[0].getHeight(context);
            width = Math.max(...widths);
            height = (this.numberOfRows - 1) * this.lineGap + this.numberOfRows * h1;
        }

        return {
            x: this.x,
            y: this.y,
            width: width,
            height: height,
        }
    }

    containsPoint(context, x, y) {
        return this.isPointInside(context, x, y)
    }

    setForceState(state) {
        if (!['normal', 'focus', 'selected'].includes(state)) {
            throw new TypeError('状态设置错误');
        }
        this.forceState = state;
    }
}


export { TextParagraph };